package com.previewlibrary.wight;

import com.previewlibrary.utils.AccelerateDecelerateInterpolator;
import com.previewlibrary.utils.SimpleStateChangedListener;
import com.previewlibrary.utils.ValueAnimator;
import com.previewlibrary.view.ImageUtils;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorGroup;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrSet;
import ohos.agp.components.PageSlider;
import ohos.agp.components.element.Element;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.PixelMapHolder;
import ohos.agp.utils.Color;
import ohos.agp.utils.Matrix;
import ohos.agp.utils.Rect;
import ohos.app.Context;
import ohos.multimodalinput.event.MmiPoint;
import ohos.multimodalinput.event.TouchEvent;

import uk.co.senab2.photoview2.Compat;
import uk.co.senab2.photoview2.PhotoView;

/**
 * author yangc
 * date 2017/4/26
 * E-Mail:yangchaojiang@outlook.com
 * Deprecated: 缩放图片
 ***/
public class SmoothImageView extends PhotoView {
    /***
     * Status.
     */
    public enum Status {
        STATE_NORMAL,
        STATE_IN,
        STATE_OUT,
        STATE_MOVE,

    }

    private static int TRANSFORM_DURATION = 400;
    private AccelerateDecelerateInterpolator interpolator = new AccelerateDecelerateInterpolator();
    private Status mStatus = Status.STATE_NORMAL;
    private static boolean ISFUll = false;
    private static boolean ISSCALE = false;
    private Paint mPaint;
    private Paint mImagePaint;
    private Matrix matrix;
    private Transform startTransform;
    private Transform endTransform;
    private Transform animTransform;
    private Rect thumbRect;
    private boolean transformStart;
    private int bitmapWidth;
    private int bitmapHeight;
    private boolean isDrag;
    AnimatorValue animator;
    private float MAX_TRANS_SCALE = 0.5f;

    public SmoothImageView(Context context) {
        this(context, null);
    }

    public SmoothImageView(Context context, AttrSet attrSet) {
        this(context, attrSet, "");

    }

    public SmoothImageView(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        initSmoothImageView();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        bitmapWidth = 0;
        bitmapHeight = 0;
        thumbRect = null;
        setFullscreen(false);
        if (animator != null) {
            animator.cancel();
            animator = null;
        }
    }


    private void initSmoothImageView() {
        mPaint = new Paint();
        mImagePaint = new Paint();
        mPaint.setStyle(Paint.Style.FILL_STYLE);
        mPaint.setColor(new Color(0xFF000000));
        matrix = new Matrix();
        setScaleType(ScaleMode.ZOOM_CENTER);
    }

    /**
     * checkMinScale .
     *
     * @return boolean
     */
    public boolean checkMinScale() {
        if (getScaleFloat() != 1) {
            setScale(1, true);
            return false;
        }
        return true;
    }

    @Override
    protected void onDrawImage(Canvas canvas) {
        if (getImageElement() == null) {
            return;
        }
        if (mStatus == Status.STATE_OUT || mStatus == Status.STATE_IN) {
            if (startTransform == null || endTransform == null || animTransform == null) {
                initTransform();
            }
            if (animTransform == null) {
                return;
            }
            mPaint.setAlpha((float) (((double) animTransform.alpha) / 255d));
            canvas.drawPaint(mPaint);
            int saveCount = canvas.getSaveCount();
            matrix.setScale(animTransform.scale, animTransform.scale);
            float translateX = -(bitmapWidth * animTransform.scale - animTransform.width) / 2;
            float translateY = -(bitmapHeight * animTransform.scale - animTransform.height) / 2;
            matrix.postTranslate(translateX, translateY);
            canvas.translate(animTransform.left, animTransform.top);
            canvas.clipRect(0, 0, animTransform.width, animTransform.height);
            canvas.concat(matrix);
            Element imageElement = getImageElement();
            canvas.drawPixelMapHolder(new PixelMapHolder(Compat.elementToPixelMap(imageElement)), 0, 0, mImagePaint);
            canvas.restoreToCount(saveCount);
            if (transformStart) {
                startTransform();
            }
        } else if (mStatus == Status.STATE_MOVE) {
            mPaint.setAlpha(0);
            canvas.drawPaint(mPaint);
            super.onDrawImage(canvas);
        } else {
            mPaint.setAlpha(1);
            canvas.drawPaint(mPaint);
            super.onDrawImage(canvas);
        }
    }

    private int downX, downY;
    private boolean isMoved = false;
    private boolean isDownPhoto = false;
    private int alpha = 0;
    private static final int MIN_TRANS_DEST = 5;

    private void actionDown(TouchEvent event) {
        MmiPoint pointerPosition = event.getPointerScreenPosition(event.getIndex());
        downX = (int) pointerPosition.getX();
        downY = (int) pointerPosition.getY();
        if (markTransform == null) {
            initTransform();
        }
        isDownPhoto = false;
        if (markTransform != null) {
            int startY = (int) markTransform.top;
            int endY = (int) (markTransform.height + markTransform.top);
            if (downY >= startY && endY >= downY) {
                isDownPhoto = true;
            }
        }
        isMoved = false;
        if (mAttacher.getPageSlider() != null) {
            mAttacher.getPageSlider().setEnabled(false);
        }
    }

    private boolean actionMove(TouchEvent event) {
        if (!isDownPhoto && event.getPointerCount() == 1) {
            return super.dispatchTouchEvent(event);
        }
        MmiPoint pointerPosition = event.getPointerScreenPosition(event.getIndex());
        int mx = (int) pointerPosition.getX();
        int my = (int) pointerPosition.getY();

        int offsetX = mx - downX;
        int offsetY = my - downY;

        // 水平方向移动不予处理
        boolean s = !isMoved && (Math.abs(offsetX) > Math.abs(offsetY) || Math.abs(offsetY) < MIN_TRANS_DEST);
        if (s) {
            return super.dispatchTouchEvent(event);
        } else {
            if (isDrag) {
                return super.dispatchTouchEvent(event);
            }
            // 一指滑动时，才对图片进行移动缩放处理
            if (event.getPointerCount() == 1) {
                if (mAttacher.getPageSlider() != null) {
                    mAttacher.getPageSlider().setEnabled(false);
                }
                mStatus = Status.STATE_MOVE;
                offsetLeftAndRight(offsetX);
                offsetTopAndBottom(offsetY);
                float scale = moveScale();

                float scaleXY = 1 - scale * 0.1f;
                setScaleY(scaleXY);
                setScaleX(scaleXY);
                isMoved = true;
                alpha = (int) (255 * (1 - scale * 0.5f));
                invalidate();
                if (alpha < 0) {
                    alpha = 0;
                }
                if (alphaChangeListener != null) {
                    alphaChangeListener.onAlphaChange(alpha);
                }
                return true;
            } else {
                return super.dispatchTouchEvent(event);
            }
        }
    }

    /**
     * 修改组件的位置来达到滚动的效果，这个方法只修改组件的垂直位置.
     *
     * @param offset offset
     */
    public void offsetTopAndBottom(int offset) {
        setTranslationY(offset);
    }

    /**
     * 修改组件的位置来达到滚动的效果，这个方法只修改组件的水平位置.
     *
     * @param offset offset
     */
    public void offsetLeftAndRight(int offset) {
        setTranslationX(offset);
    }

    private boolean actionCancel() {
        if (moveScale() <= MAX_TRANS_SCALE) {
            moveToOldPosition();
        } else {
            changeTransform();
            if (transformOutListener != null) {
                transformOutListener.onTransformOut();
            }
        }
        if (mAttacher.getPageSlider() != null) {
            mAttacher.getPageSlider().setEnabled(true);
        }
        return true;
    }

    private boolean dispatchTouchEventIsscale(TouchEvent event) {
        int action = event.getAction();
        if (getScaleFloat() == 1) {
            switch (action) {
                case TouchEvent.PRIMARY_POINT_DOWN:
                    actionDown(event);
                    break;
                case TouchEvent.POINT_MOVE:
                    return actionMove(event);
                case TouchEvent.PRIMARY_POINT_UP:
                case TouchEvent.CANCEL:
                    if (isMoved) {
                        return actionCancel();
                    }
                    break;
                default: {
                }
            }
        } else {
            switch (action) {
                case TouchEvent.PRIMARY_POINT_UP:
                case TouchEvent.CANCEL:
                    if (isMoved) {
                        return actionCancel();
                    }
                    break;
                default: {
                }
            }
        }
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean dispatchTouchEvent(TouchEvent event) {
        if (mAttacher.getPageSlider() != null) {
            int currentSlidingState = mAttacher.getPageSlider().getCurrentSlidingState();
            if (currentSlidingState == PageSlider.SLIDING_STATE_DRAGGING) {
                return super.dispatchTouchEvent(event);
            }
        }
        int action = event.getAction();
        if (ISSCALE) {
            return dispatchTouchEventIsscale(event);
        } else {
            switch (action) {
                case TouchEvent.PRIMARY_POINT_DOWN:
                    actionDown(event);
                    break;
                case TouchEvent.POINT_MOVE:
                    return actionMove(event);
                case TouchEvent.PRIMARY_POINT_UP:
                case TouchEvent.CANCEL:
                    if (isMoved) {
                        return actionCancel();
                    }
                    break;
                default: {
                }
            }
        }
        return super.dispatchTouchEvent(event);
    }

    /**
     * 未达到关闭的阈值松手时，返回到初始位置.
     */
    private void moveToOldPosition() {
        ValueAnimator va = ValueAnimator.ofInt((int) getTranslationY(), 0);
        va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            int startValue = 0;

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int value = (int) animation.getAnimatedValue();
                if (startValue != 0) {
                    offsetTopAndBottom(value - startValue);
                }
                startValue = value;
            }
        });

        ValueAnimator leftAnim = ValueAnimator.ofInt((int) getTranslationX(), 0);
        leftAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            int startValue = 0;

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int value = (int) animation.getAnimatedValue();
                if (startValue != 0) {
                    offsetLeftAndRight(value - startValue);
                }
                startValue = value;
            }
        });
        ValueAnimator alphaAnim = ValueAnimator.ofInt(alpha, 255);
        alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                if (alphaChangeListener != null) {
                    alphaChangeListener.onAlphaChange((Integer) animation.getAnimatedValue());
                }
            }
        });

        ValueAnimator scaleAnim = ValueAnimator.ofFloat(getScaleX(), 1);
        scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float scale = (float) animation.getAnimatedValue();
                setScaleX(scale);
                setScaleY(scale);
            }
        });
        AnimatorGroup as = new AnimatorGroup();
        as.setDuration(TRANSFORM_DURATION);
        as.runParallel(va, leftAnim, scaleAnim, alphaAnim);
        as.start();
    }

    private float moveScale() {
        if (markTransform == null) {
            initTransform();
        }
        return Math.abs(getTranslationY() / markTransform.height);
    }

    private OnAlphaChangeListener alphaChangeListener;
    private OnTransformOutListener transformOutListener;

    /**
     * setTransformOutListener.
     *
     * @param transformOutListener transformOutListener
     */
    public void setTransformOutListener(OnTransformOutListener transformOutListener) {
        this.transformOutListener = transformOutListener;
    }

    /**
     * setAlphaChangeListener .
     *
     * @param alphaChangeListener alphaChangeListener
     */
    public void setAlphaChangeListener(OnAlphaChangeListener alphaChangeListener) {
        this.alphaChangeListener = alphaChangeListener;
    }

    /**
     * OnTransformOutListener.
     */
    public interface OnTransformOutListener {
        /**
         * onTransformOut.
         */
        void onTransformOut();
    }

    /**
     * OnAlphaChangeListener.
     */
    public interface OnAlphaChangeListener {
        /**
         * onAlphaChange.
         *
         * @param alpha alpha
         */
        void onAlphaChange(int alpha);
    }

    private Transform markTransform;

    private void changeTransform() {
        if (markTransform != null) {
            Transform tempTransform = markTransform.clone();
            tempTransform.top = markTransform.top + getTranslationY();
            tempTransform.left = markTransform.left + getTranslationX();
            tempTransform.alpha = alpha;
            tempTransform.scale = markTransform.scale - (1 - getScaleX()) * markTransform.scale;
            animTransform = tempTransform.clone();
            endTransform = tempTransform.clone();
        }
    }

    private void setStartTransform(float va) {
        if (mStatus == Status.STATE_IN) {
            animTransform.scale = interpolator.getCurrentValue(va,
                    startTransform.scale, endTransform.scale);
            animTransform.alpha = interpolator.getCurrentValue(va,
                    startTransform.alpha, endTransform.alpha);
            animTransform.left = interpolator.getCurrentValue(va,
                    startTransform.left, endTransform.left);
            animTransform.top = interpolator.getCurrentValue(va,
                    startTransform.top, endTransform.top);
            animTransform.width = interpolator.getCurrentValue(va,
                    startTransform.width, endTransform.width);
            animTransform.height = interpolator.getCurrentValue(va,
                    startTransform.height, endTransform.height);
        } else {
            animTransform.scale = interpolator.getCurrentValue(va,
                    endTransform.scale, startTransform.scale);
            animTransform.alpha = interpolator.getCurrentValue(va,
                    endTransform.alpha, startTransform.alpha);
            animTransform.left = interpolator.getCurrentValue(va,
                    endTransform.left, startTransform.left);
            animTransform.top = interpolator.getCurrentValue(va,
                    endTransform.top, startTransform.top);
            animTransform.width = interpolator.getCurrentValue(va,
                    endTransform.width, startTransform.width);
            animTransform.height = interpolator.getCurrentValue(va,
                    endTransform.height, startTransform.height);
        }
        invalidate();
    }

    private void startTransform() {
        transformStart = false;
        if (animTransform == null) {
            return;
        }
        animator = new AnimatorValue();
        animator.setDuration(TRANSFORM_DURATION);
        animator.setValueUpdateListener((animatorValue, va) -> setStartTransform(va));
        animator.setStateChangedListener(new SimpleStateChangedListener() {
            @Override
            public void onEnd(Animator animator) {
                super.onEnd(animator);
                if (onTransformListener != null) {
                    onTransformListener.onTransformCompleted(mStatus);
                }
                if (mStatus == Status.STATE_IN) {
                    mStatus = Status.STATE_NORMAL;
                }
            }
        });
        animator.start();

    }

    public void transformIn(OnTransformListener listener) {
        setOnTransformListener(listener);
        transformStart = true;
        mStatus = Status.STATE_IN;
        invalidate();
    }

    public void transformOut(OnTransformListener listener) {
        if (getTranslationY() != 0) {
            offsetTopAndBottom(0);
        }
        if (getTranslationX() != 0) {
            offsetLeftAndRight(0);
        }
        if (getScaleX() != 1) {
            setScaleX(1);
            setScaleY(1);
        }
        setOnTransformListener(listener);
        transformStart = true;
        mStatus = Status.STATE_OUT;
        invalidate();
    }

    /**
     * 设置起始位置图片的Rect.
     * g
     *
     * @param thumbRect 参数
     */
    public void setThumbRect(Rect thumbRect) {
        this.thumbRect = thumbRect;
    }

    private void initTransform() {
        if (getImageElement() == null) {
            return;
        }
        if (startTransform != null && endTransform != null && animTransform != null) {
            return;
        }
        if (getWidth() == 0 || getHeight() == 0) {
            return;
        }
        int width = getImageElement().getWidth();
        int height = getImageElement().getHeight();
        bitmapWidth = width;
        bitmapHeight = height;
        startTransform = new Transform();
        startTransform.alpha = 0;
        if (thumbRect == null) {
            thumbRect = new Rect();
        }
        startTransform.left = thumbRect.left;
        if (ISFUll) {
            startTransform.top = thumbRect.top;
        } else {
            startTransform.top = thumbRect.top -
                    ImageUtils.getStatusBarHeight(getContext().getApplicationContext());
        }
        startTransform.width = thumbRect.getWidth();
        startTransform.height = thumbRect.getHeight();
        // 开始时以CenterCrop方式显示，缩放图片使图片的一边等于起始区域的一边，另一边大于起始区域
        float startScaleX = (float) thumbRect.getWidth() / bitmapWidth;
        float startScaleY = (float) thumbRect.getHeight() / bitmapHeight;
        startTransform.scale = startScaleX > startScaleY ? startScaleX : startScaleY;

        // 结束时以fitCenter方式显示，缩放图片使图片的一边等于View的一边，另一边大于View
        float endScaleX = (float) getWidth() / bitmapWidth;
        float endScaleY = (float) getHeight() / bitmapHeight;
        endTransform = new Transform();
        endTransform.scale = endScaleX < endScaleY ? endScaleX : endScaleY;
        endTransform.alpha = 255;
        int endBitmapWidth = (int) (endTransform.scale * bitmapWidth);
        int endBitmapHeight = (int) (endTransform.scale * bitmapHeight);
        endTransform.left = (getWidth() - endBitmapWidth) / 2;
        endTransform.top = (getHeight() - endBitmapHeight) / 2;
        endTransform.width = endBitmapWidth;
        endTransform.height = endBitmapHeight;

        if (mStatus == Status.STATE_IN) {
            animTransform = startTransform.clone();
        } else if (mStatus == Status.STATE_OUT) {
            animTransform = endTransform.clone();
        }
        markTransform = endTransform;

    }

    private OnTransformListener onTransformListener;

    /**
     * setOnTransformListener .
     *
     * @param onTransformListener onTransformListener
     */
    public void setOnTransformListener(OnTransformListener onTransformListener) {
        this.onTransformListener = onTransformListener;
    }

    /**
     * onTransformListener.
     */
    public interface OnTransformListener {
        /**
         * onTransformCompleted.
         *
         * @param status status
         */
        void onTransformCompleted(Status status);

    }

    private static class Transform implements Cloneable {
        float left, top, width, height;
        float alpha;
        float scale;

        @Override
        public Transform clone() {
            Transform obj = null;
            try {
                obj = (Transform) super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return obj;
        }
    }


    /**
     * 设置图片拖拽返回.
     *
     * @param isDrag      true  可以 false 默认 true
     * @param sensitivity sensitivity
     **/
    public void setDrag(boolean isDrag, float sensitivity) {
        this.isDrag = isDrag;
        this.MAX_TRANS_SCALE = sensitivity;
    }

    /**
     * 设置动画的时长.
     *
     * @param duration 单位毫秒
     **/
    public static void setDuration(int duration) {
        TRANSFORM_DURATION = duration;
    }

    /**
     * 获取动画的时长.
     *
     * @return int
     **/
    public static int getDuration() {
        return TRANSFORM_DURATION;
    }

    /**
     * 设置是否全屏.
     *
     * @param isFull true 全屏
     **/
    public static void setFullscreen(boolean isFull) {
        ISFUll = isFull;
    }

    /**
     * 设置只有图片没有放大或者的缩小状态触退出.
     *
     * @param isScale true false
     **/
    public static void setIsScale(boolean isScale) {
        ISSCALE = isScale;
    }
}
